﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Input;
using Avivo.Tools.Sprite.Models;

namespace Avivo.Tools.Sprite
{
	public class GenerateSpriteCommand : ICommand
	{
		#region Private members
		private SpriteViewModel parent;
		#endregion

		#region Constructor
		public GenerateSpriteCommand(SpriteViewModel parent)
		{
			this.parent = parent;
		}
		#endregion

		#region ICommand Members
		public bool CanExecute(object parameter)
		{
			return true;
		}

		public event EventHandler CanExecuteChanged;

		public void Execute(object parameter)
		{
			RenderSprite(
				this.parent.Sprites,
				this.parent.EnableCss,
				this.parent.BaseClassName,
				this.parent.InputDirectory,
				this.parent.OutputDirectory,
				this.parent.BuildSampleHtml);
		}
		#endregion

		#region Protected methods
		/// <summary>
		/// Generates a .css and a .png sprite and returns html code to include .css ('link' tag).
		/// </summary>
		protected void RenderSprite(ObservableCollection<SpriteModel> sprites, bool generateCss, string baseClassName, string inputDirectory, string outputDirectory, bool buildSampleHtml)
		{
			const string spriteTemplate = "a.{0} {{ background-image: url('{1}'); }}";
			const string normalTemplate = "a.{0} {{ background-position: -{3}px -{4}px; display: block; width: {1}px; height: {2}px; }}";
			const string hoverTemplate = "a.{0}:hover {{ background-position: -{3}px -{4}px; display: block; width: {1}px; height: {2}px; }}";
			const string customTemplate = "a.{0} .[CUSTOM] {{ background-position: -{3}px -{4}px; display: block; width: {1}px; height: {2}px; }}";

			StringBuilder builder = new StringBuilder();

			try
			{
				string absoluteSpriteUrl = baseClassName + ".png";
				string physicalSpritePath = Path.Combine(outputDirectory, baseClassName + ".png");
				string physicalCssPath = Path.Combine(outputDirectory, baseClassName + ".css");
				string physicalHtmlPath = Path.Combine(outputDirectory, baseClassName + ".htm");
				string templateDirectory = inputDirectory;

				if (!Directory.Exists(outputDirectory))
				{
					Directory.CreateDirectory(outputDirectory);
				}

				if (File.Exists(physicalCssPath))
				{
					File.Delete(physicalCssPath);
				}

				if (File.Exists(physicalSpritePath))
				{
					File.Delete(physicalSpritePath);
				}

				builder.AppendFormat(spriteTemplate, baseClassName, absoluteSpriteUrl);
				builder.AppendLine();

				#region Prepare input
				SpriteGrid grid = new SpriteGrid();
				foreach (var item in sprites)
				{
					SpriteRow row = new SpriteRow();

					var styles = GetSpriteStyles(templateDirectory, item.Template);
					foreach (var style in styles)
					{
						row.Add(
							new SpriteItem()
							{
								Name = item.Name,
								Text = item.Content,
								Source = Path.Combine(templateDirectory, string.Format("{0}_{1}.xaml", item.Template, style)), // "_normal.xaml"),
								Style = style,
							});
					}

					grid.Add(row);
				}
				#endregion

				#region Generate output
				bool spriteExist = false;
				//if (useXSprite) //UseExternalProcess
				//{
				//  spriteExist = Program.GenerateSprite(ref grid, physicalSpritePath);
				//}
				//else
				{
					spriteExist = Program.GenerateSpriteWithoutExternalProcess(ref grid, physicalSpritePath);
				}
				if (spriteExist)
				{
					//Referenced rows have been updated with width, height, x and y values
					foreach (var row in grid)
					{
						foreach (var item in row)
						{
							if (!string.IsNullOrEmpty(item.Style))
							{
								var t = normalTemplate;
								switch (item.Style.ToLower())
								{
									case "normal": //e.g. item_normal.xaml
										t = normalTemplate;
										break;

									case "hover": //e.g. item_hover.xaml
										t = hoverTemplate;
										break;

									default: //e.g. item_selected.xaml or item_hidden.xaml
										t = customTemplate.Replace("[CUSTOM]", item.Style);
										break;
								}
								builder.AppendFormat(t, item.Name, item.Width, item.Height, item.X, item.Y);
								builder.AppendLine();
							}
						}

						////Normal
						//var normal = row[0];
						//builder.AppendFormat(normalTemplate, normal.Name, normal.Width, normal.Height, normal.X, normal.Y);
						//builder.AppendLine();

						////Mouse over
						//var hover = row[1];
						//builder.AppendFormat(hoverTemplate, hover.Name, hover.Width, hover.Height, hover.X, hover.Y);
						//builder.AppendLine();

						////Selected
						//var selected = row[2];
						//builder.AppendFormat(hoverTemplate, selected.Name, selected.Width, selected.Height, selected.X, selected.Y);
						//builder.AppendLine();
					}
				}
				#endregion

				//Create a .css file
				File.WriteAllText(physicalCssPath, builder.ToString());

				if (buildSampleHtml)
				{
					BuildSampleHtml(sprites, baseClassName, physicalCssPath, physicalHtmlPath);
				}
			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.Message + Environment.NewLine + ex.StackTrace);
			}
		}

		protected void BuildSampleHtml(ObservableCollection<SpriteModel> sprites, string baseClassName, string cssFile, string targetHtmlFile)
		{
			StringBuilder builder = new StringBuilder();
			builder.AppendLine("<html>");
			builder.AppendLine("<head>");
			builder.AppendLine("<title>Sprite Generator</title>");
			builder.AppendLine("<link rel=\"stylesheet\" type=\"text/css\" href=\"" + Path.GetFileName(cssFile) + "\" />");
			builder.AppendLine("</head>");
			builder.AppendLine("<body>");
			builder.AppendLine();

			builder.AppendFormat("<h2>HTML sample generated with {0} v{1} at {2}</h2>", Settings.ProductName, Settings.ProductVersion, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")).AppendLine();

			StringBuilder samples = new StringBuilder();
			foreach (var item in sprites)
			{
				samples.AppendFormat("<a href=\"#\" class=\"{0} {1}\"></a><br />", baseClassName, item.Name).AppendLine();
			}
			builder.AppendLine(samples.ToString());

			builder.AppendLine("<hr />");
			builder.AppendLine("<h2>CSS</h2>");
			builder.Append("<textarea style=\"width: 100%; height: 300px;\">").Append(File.ReadAllText(cssFile)).AppendLine("</textarea>");
			builder.AppendLine();

			builder.AppendLine("<hr />");
			builder.AppendLine("<h2>HTML</h2>");
			builder.Append("<textarea style=\"width: 100%; height: 300px;\">").Append(samples.ToString()).AppendLine("</textarea>");

			builder.AppendLine("<hr />");
			builder.AppendLine("<h2>Image</h2>");
			builder.AppendFormat("<img src=\"{0}\" alt=\"{0}\" title=\"{0}\">", Path.ChangeExtension(Path.GetFileName(cssFile), ".png")).AppendLine();

			builder.AppendLine();
			builder.AppendLine("</body>");
			builder.AppendLine("</html>");
			File.WriteAllText(targetHtmlFile, builder.ToString());

			Process.Start(targetHtmlFile);
		}

		protected List<string> GetSpriteStyles(string templateDirectory, string name)
		{
			var result = new List<string>();
			var pattern = new Regex(name + @"_([\w\d]+).xaml", RegexOptions.IgnoreCase);
			var templates = Directory.GetFiles(templateDirectory, "*.xaml", SearchOption.TopDirectoryOnly);
			foreach (var template in templates)
			{
				var match = pattern.Match(template);
				if (match.Success)
				{
					string style = match.Groups[1].Value;
					if (!result.Contains(style))
					{
						result.Add(style);
					}
				}
			}
			return result;
		}
		#endregion
	}
}
